@file:Suppress("SpellCheckingInspection")

package han.cirno.corrupt.components.school.impl.mju

import han.cirno.corrupt.R
import han.cirno.corrupt.data.instances.UserSchoolData
import han.cirno.corrupt.components.school.SchoolImpl
import han.cirno.corrupt.components.school.SchoolProvider
import han.cirno.corrupt.components.school.impl.CommonNetClient
import han.cirno.corrupt.throwables.LoginExceptions
import han.cirno.corrupt.util.OkHttpUtil.quickCall
import han.cirno.corrupt.util.getBodyStringAndClose
import okhttp3.FormBody
import okhttp3.Request
import okhttp3.Response
import org.json.JSONObject
import org.jsoup.Jsoup
import kotlin.random.Random

/**
 * 这回能好看点吗
 * @author CCirno
 */
class MjuEduClient: CommonNetClient<MjuEduConst.Payload>(
    {Request.Builder().url("https://authserver.mju.edu.cn/authserver/login?service=https%3A%2F%2Fjwgl.mju.edu.cn%2Fsso%2Fzfiotlogin").build()},
    { MjuEduConst.isLoopBackedToLogin(it) }) {
    companion object{
        val instance: MjuEduClient = MjuEduClient()
    }

    override fun tryLogin(tryLoginResponse: Response){
        val implCookieJar=implCookieJarSource()
        val preLoginResponse = okHttpClient.newCall(
            Request.Builder()
                .url(tryLoginResponse.request.url.toString())
                .build()
        ).execute().getBodyStringAndClose()!!
        tryLoginResponse.close()
        val preLoginDocument = Jsoup.parse(preLoginResponse)
        val execution = preLoginDocument.getElementById("fm1")!!.getElementsByAttributeValue("name", "execution").attr("value")
        val (modulus, publicExponent) = fetchPublicKey()
        val data = SchoolImpl.impl!!.dataOperation()
        val username = data.singleGet(SchoolProvider.KEY_ID, String::class)!!
        val password=data.singleGet(SchoolProvider.KEY_PASSWORD,String::class)!!
        val formBody = FormBody.Builder()
            .add("username", username)
            .add("password", MjuEduConst.encrypt(modulus, publicExponent, password))
            .add("authcode", "")
            .add("execution", execution)
            .add("_eventId", "submit")
            .build()
        val (body,httpCode,url)=okHttpClient.quickCall(
            Request.Builder()
                .url("https://authserver.mju.edu.cn/authserver/login?v=${Random.nextFloat()}")
                .post(formBody))
            .use { Triple(it.body!!.string(),it.code,it.request.url) }
        val document = Jsoup.parse(body)
        if (!MjuEduConst.isLoopBackedToLogin(url)) {
            return
        }
        SchoolImpl.getImpl(UserSchoolData.School.MJU)?.dataOperation()
            ?.write(MjuSchool.KEY_SESSION_ID,implCookieJar.cookies.find { c->c.name=="JSESSIONID" })
            ?.save()
        if(httpCode in 200..299) {
            val errorMsg = document.getElementById("errormsg")!!.text()
            if (errorMsg.contains("错误"))
                throw LoginExceptions.InvalidDataExceptionWithResId(R.string.login_error_login_invalidData_password_unknown_times,null)
            if (errorMsg.contains("录入密码"))
                throw LoginExceptions.InvalidDataExceptionWithResId(R.string.login_error_login_invalidData_emptyPassword,null)
            if (errorMsg.contains("录入用户名"))
                throw LoginExceptions.InvalidDataExceptionWithResId(R.string.login_error_login_invalidData_emptyUsername,null)
            if (errorMsg.contains("请打开新页面"))
                throw LoginExceptions.NetworkExceptionWithResId(R.string.login_error_network,null)
            throw LoginExceptions.InvalidDataExceptionWithResId(R.string.login_error_login_invalidData_other,null,errorMsg)
        }
        throw Exception("Http Error: $httpCode")
    }

    private fun fetchPublicKey():Pair<String, String>{
        return okHttpClient.quickCall(Request.Builder()
            .url("https://authserver.mju.edu.cn/authserver/v2/getPubKey")).use {
            val body = it.body!!.string()
            val jsonObject = JSONObject(body)
            MjuEduConst.fillZero(jsonObject.getString("modulus")) to
                    MjuEduConst.fillZero(jsonObject.getString("exponent"))
        }
    }

}